<?php

namespace app\logic\user;

use app\common\enum\AccountTypeEnum;
use app\common\model\BindFacebook;
use app\common\model\BindGoogle;
use app\common\model\BindTwitter;
use app\common\model\User;
use app\logic\provider\FacebookProxy;
use app\logic\provider\GoogleProxy;
use app\logic\provider\TwitterProxy;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Overtrue\Socialite\SocialiteManager;
use think\facade\Log;
use GuzzleHttp\Middleware;

class SocialiteLogic
{

    /**
     * 获取Socialite管理器实例
     * @return SocialiteManager
     */
    public static function getSocialiteManager(): SocialiteManager
    {
        // 加载社交认证配置信息
        $config = config('socialite.account');

        // 实例化Socialite管理器，用于处理与第三方社交平台的交互
        $socialite = new SocialiteManager($config);

        //追加拓展 twitter
        $socialite->extend('twitter', function (array $config) {
            return new TwitterProxy($config);
        });
        //追加拓展 google_proxy
        $socialite->extend('google_proxy', function (array $config) {
            return new GoogleProxy($config);
        });
        //追加拓展 facebook_proxy
        $socialite->extend('facebook_proxy', function (array $config) {
            return new FacebookProxy($config);
        });
        //追加拓展 twitter_proxy
        $socialite->extend('twitter_proxy', function (array $config) {
            return new TwitterProxy($config);
        });

        return $socialite;
    }

    /**
     * 登录方法
     * 该方法用于通过社交平台进行用户登录
     * 它通过社交平台提供的授权码来获取用户信息，并根据平台不同调用相应的处理方法
     *
     * @param string $platform 社交平台标识，例如google、facebook等
     * @param string $code 社交平台提供的授权码
     * @return mixed 根据不同的社交平台，返回不同的处理结果
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function login(string $platform, string $code, $bindUserInfo = []): mixed
    {
        try {
            $socialite = SocialiteLogic::getSocialiteManager();
            // 根据平台标识和授权码获取用户信息
            $name = $platform;
            if (config('socialite.proxy.switch')) {
                $name = $platform.'_proxy';
            }
            $platformUser = $socialite->create($name)->userFromCode($code);
        } catch (\Throwable $exception) {
            Log::channel('my')->error($exception->getMessage() . "\n" . $exception->getTraceAsString());
            throw $exception;
        }

        // 根据社交平台标识调用对应的方法处理用户信息
        $platformBindModel = call_user_func_array([__CLASS__, $platform], [$platformUser]);

        $isNew = false;
        // 如果用户还没有已绑定
        if (!$platformBindModel->user_id) {
            $isNew = true;
            User::where('id', $bindUserInfo['id'])->update([
                'avatar' => $platformUser->getAvatar(),
                'nickname' => $platformUser->getNickname(),
                'account_type' => AccountTypeEnum::TEXT[$platform]
            ]);
            // 创建新用户
            $userId = $bindUserInfo['id'];
            $platformBindModel->user_id = $userId;
            $platformBindModel->save();
        } else {
            $userId = $platformBindModel->user_id;
        }

        $user = User::where('id', $userId)->find();
        $user->setAttr('is_new', $isNew);
        return $user;
    }

    /**
     * 创建新用户
     *
     * 此方法用于根据社交媒体用户数据创建本站的新用户主要用于社交账号登录或绑定时
     * 它将使用社交用户数据填充新用户模型的字段，并保存到数据库中
     *
     * @param \Overtrue\Socialite\User $user 社交媒体用户对象，包含社交用户信息
     * @return User 本站新创建的用户模型对象
     */
    private static function createNewUser(\Overtrue\Socialite\User $user): User
    {
        // 根据社交媒体用户数据初始化本站用户模型
        $userModel = new User([
            'username' => "user_" . uniqid(),
            'nickname' => $user->getNickname(),
            'email' => $user->getEmail() ?: '',
            'avatar' => $user->getAvatar() ?: '',
            'join_ip' => request()->ip(),
            'join_time' => request()->time(),
            'password' => '',
            'status' => 'enable',
            'group_id' => 1,
        ]);

        // 保存新用户到数据库
        $userModel->save();

        // 返回新创建的用户模型对象
        return $userModel;
    }


    /**
     * 处理Google用户登录
     *
     * 此方法用于处理通过Google账号登录的用户它首先尝试在数据库中查找是否已存在该用户
     * 如果用户存在，则直接返回用户信息如果用户不存在，则创建新用户，并返回新用户信息
     *
     * @param \Overtrue\Socialite\User $user 代表Google用户的实例，包含用户的基本信息
     * @return mixed 返回用户模型实例或根据用户情况执行的其他操作
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \Exception
     */
    protected static function google(\Overtrue\Socialite\User $user): mixed
    {
        // 获取Google用户的ID
        $platform_id = $user->getId();

        // 检查平台ID是否有效
        if (empty($platform_id)) {
            throw new \InvalidArgumentException("Invalid platform ID");
        }

        try {
            // 尝试在绑定表中查找是否存在该Google用户
            $find = BindGoogle::where('platform_id', $platform_id)->find();
            // 如果用户已部分绑定，更新绑定表
            if (!$find) {
                // 创建新的Google绑定实例并保存绑定信息
                $find = new BindGoogle([
                    'platform_id' => $platform_id,
                    'user_id' => 0,
                    'nickname' => $user->getNickname(),
                    'email' => $user->getEmail() ?: '',
                    'avatar' => $user->getAvatar(),
                ]);
                $find->save();
            }
            return $find;
        } catch (\Exception $e) {
            // 记录异常日志
            Log::channel('my')->error("Error in Google login: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * 处理Facebook用户登录和绑定
     *
     * 此方法主要用于处理Facebook用户的登录过程，包括验证用户身份、检查用户是否已绑定，
     * 以及对未绑定用户进行绑定操作
     *
     * @param \Overtrue\Socialite\User $user Facebook用户信息对象，包含用户的基本信息
     *
     * @return mixed 返回绑定信息对象，如果发生异常则抛出异常
     *
     * @throws \InvalidArgumentException 如果平台ID无效，则抛出此异常
     * @throws \Exception 对于其他类型的异常，捕获并重新抛出
     */
    protected static function facebook(\Overtrue\Socialite\User $user): mixed
    {
        // 获取facebook用户的ID
        $platform_id = $user->getId();

        // 检查平台ID是否有效
        if (empty($platform_id)) {
            throw new \InvalidArgumentException("Invalid platform ID");
        }

        try {
            // 尝试在绑定表中查找是否存在该Google用户
            $find = BindFacebook::where('platform_id', $platform_id)->find();
            // 如果用户已部分绑定，更新绑定表
            if (!$find) {
                // 创建新的Google绑定实例并保存绑定信息
                $find = new BindFacebook([
                    'platform_id' => $platform_id,
                    'user_id' => 0,
                    'name' => $user->getName() ?: '',
                    'nickname' => $user->getNickname(),
                    'email' => $user->getEmail() ?: '',
                    'avatar' => $user->getAvatar(),
                ]);
                $find->save();
            }
            return $find;
        } catch (\Exception $e) {
            // 记录异常日志
            Log::channel('my')->error("Error in Facebook login: " . $e->getMessage());
            throw $e;
        }
    }

    protected static function twitter(\Overtrue\Socialite\User $user)
    {
        // 获取Google用户的ID
        $platform_id = $user->getId();

        // 检查平台ID是否有效
        if (empty($platform_id)) {
            throw new \InvalidArgumentException("Invalid platform ID");
        }

        try {
            // 尝试在绑定表中查找是否存在该Google用户
            $find = BindTwitter::where('platform_id', $platform_id)->find();
            // 如果用户已部分绑定，更新绑定表
            if (!$find) {
                // 创建新的Google绑定实例并保存绑定信息
                $find = new BindTwitter([
                    'platform_id' => $platform_id,
                    'user_id' => 0,
                    'nickname' => $user->getName() ?: '',
                    'email' => $user->getEmail() ?: '',
                    'avatar' => $user->getAvatar() ?: '',
                ]);
                $find->save();
            }
            return $find;
        } catch (\Exception $e) {
            // 记录异常日志
            Log::channel('my')->error("Error in Google login: " . $e->getMessage());
            throw $e;
        }
    }

}